/**
 * Copyright (c) 2022 Shanghai Fullhan Microelectronics Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 *
 * Change Logs:
 */

#include <common.h>
#include <environment.h>
#include <asm/io.h>
#include <asm/arch/hardware.h>
#include <usb.h>
#include <phy.h>
#include <spi.h>
#include <dwc3-uboot.h>
#include <mmc.h> 
DECLARE_GLOBAL_DATA_PTR;
#define MAX_MAC_CTL    1
#define CONFIG_GPIO_EMAC_0_PHY_RESET	128
#define CONFIG_GPIO_EMAC_1_PHY_RESET	128
struct phy_reg_cfg phy_config_array[] = {
	{
		.id = FH_GMAC_PHY_RTL8201,
		.list = {
			{W_PHY, 0x1f, 0x7},
			{W_PHY, 0x10, 0x1ff4},
			{W_PHY, 0x1f, 0},
			{W_PHY, 0x0d, 0x07},
			{W_PHY, 0x0e, 0x3c},
			{W_PHY, 0x0d, 0x4007},
			{W_PHY, 0x0e, 0x0},
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{
		.id = FH_GMAC_PHY_INTERNAL_V2,
		.list = {
			{0},
		},
		.inf_sup = PHY_INTERFACE_MODE_MII,
	},
	{0},
};


/* Get boot mode */
int get_boot_media(void)
{
	int boot_mode;

	boot_mode = GET_REG(REG_PMU_BOOT_MODE);

	return boot_mode;
}

void fh_external_phy_0_reset(void)
{

#if(0)		
	gpio_direction_output(CONFIG_GPIO_EMAC_0_PHY_RESET, 1);
	udelay(150000);
	gpio_direction_output(CONFIG_GPIO_EMAC_0_PHY_RESET, 0);
	udelay(10000);
	gpio_direction_output(CONFIG_GPIO_EMAC_0_PHY_RESET, 1);
	udelay(100000);
#endif
}


int gmac_0_set_spd(int speed){
	int reg;
	//TBD
	//soc just need to set mac control reg
}

int phy_0_sel_func(struct phy_device *phydev, int phy_sel)
{
#if(0)
	if(phy_sel == EXTERNAL_PHY){
		//external phy sel
		//external phy enable
		SET_REG_M(0x24100178, 1, 0x3);
		//open external phy clk
		SET_REG_M(0x24100178, 1 << 20, 1 << 20);
	}
	else{
		//close external phy clk
		SET_REG_M(0x24100178, 0 << 20, 1 << 20);
		//internal phy sel
		//enable internal phy
		SET_REG_M(0x24100178, 0, 0x3);
		//open internal phy clk
		SET_REG_M(0x2410017c, 1 << 20, 1 << 20);
		//ephy reset
		SET_REG_M(0x24100178, 1 << 4, 1 << 4);
		//maybe need delay?
		SET_REG_M(0x24100178, 0, 1 << 4);
	}
#endif
}

static struct gmac_plat_info gmac_plat_data[] = {
	{
		.regs = GMAC0_REG_BASE,
		.id = 0,
		.phy_driver_list[0] = "Generic PHY 0",
		.phy_driver_list[1] = 0,
		.p_cfg_array = phy_config_array,
	},
};

void *get_platform_eth_info(unsigned int id){
	return &gmac_plat_data[id];
}


int phy_0_inf_set(struct phy_device *phydev, int inf){

#if(0)
	if (inf == PHY_INTERFACE_MODE_RGMII){
		printf("unsupport RGMII...\n");
		return -1;
	}

	if(inf == PHY_INTERFACE_MODE_RMII){
		//rmii interface select, [15:13] b'100 == rmii
		SET_REG_M(0x24100178, 0x8000, 0xe000);
	}
	else{
		SET_REG_M(0x24100178, 0, 0xe000);
	}
#endif
	return 0;
}


#define BITS_PER_LONG 32
#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))

static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
{
	unsigned long idx;

	for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
		if (addr[idx])
			return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
	}

	return size;
}


unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
{
	if (size) {
		unsigned long val = BITMAP_LAST_WORD_MASK(size);
		unsigned long idx = (size-1) / BITS_PER_LONG;

		do {
			val &= addr[idx];
			if (val)
				return idx * BITS_PER_LONG + __fls(val);

			val = ~0ul;
		} while (idx--);
	}
	return size;
}

enum {
	CP_VAL_0,
	CP_VAL_1,
	VAL_100M_0,
	VAL_100M_1,
	VAL_10M_0,
	VAL_10M_1,
	TRAIN_MAX_SIZE,
};

static unsigned int train_100_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static unsigned int train_10_array[] = {
	31, 30, 29, 28,
	27, 26, 25, 24,
	23, 22, 21, 20,
	19, 18, 17, 16,
	0,  1,  2,  3,
	4,  5,  6,  7,
	8,  9,  10, 11,
	12, 13, 14, 15,
};

static unsigned int train_cp_array[] = {
	0, 1, 2, 3,
};
#define REFIX_CP_TRAIN_DATA_OFFSET	    (0)
#define REFIX_100M_TRAIN_DATA_OFFSET    (0)
#define REFIX_10M_TRAIN_DATA_OFFSET	    (0)

struct s_train_val train_array[TRAIN_MAX_SIZE] = {

		[CP_VAL_0].name = "cp_val_0",
		[CP_VAL_0].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_0].src_mask = 0xc0,
		[CP_VAL_0].src_vaild_index = 15,
		[CP_VAL_0].dst_add = 0x18,
		[CP_VAL_0].dst_vaild_index = 22,
		[CP_VAL_0].bind_train_array = train_cp_array,
		[CP_VAL_0].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_0].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[CP_VAL_1].name = "cp_val_1",
		[CP_VAL_1].src_add = REG_PMU_EPHY_PARAM,
		[CP_VAL_1].src_mask = 0xc0,
		[CP_VAL_1].src_vaild_index = 15,
		[CP_VAL_1].dst_add = 0xb7c,
		[CP_VAL_1].dst_vaild_index = 6,
		[CP_VAL_1].bind_train_array = train_cp_array,
		[CP_VAL_1].bind_train_size = ARRAY_SIZE(train_cp_array),
		[CP_VAL_1].usr_train_offset =
		REFIX_CP_TRAIN_DATA_OFFSET,

		[VAL_100M_0].name = "val_100M_0",
		[VAL_100M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_0].src_mask = 0x1f,
		[VAL_100M_0].src_vaild_index = 5,
		[VAL_100M_0].dst_add = 0x24,
		[VAL_100M_0].dst_vaild_index = 8,
		[VAL_100M_0].bind_train_array = train_100_array,
		[VAL_100M_0].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_0].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_100M_1].name = "val_100M_1",
		[VAL_100M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_100M_1].src_mask = 0x1f,
		[VAL_100M_1].src_vaild_index = 5,
		[VAL_100M_1].dst_add = 0x1308,
		[VAL_100M_1].dst_vaild_index = 8,
		[VAL_100M_1].bind_train_array = train_100_array,
		[VAL_100M_1].bind_train_size = ARRAY_SIZE(train_100_array),
		[VAL_100M_1].usr_train_offset =
		REFIX_100M_TRAIN_DATA_OFFSET,

		[VAL_10M_0].name = "val_10M_0",
		[VAL_10M_0].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_0].src_mask = 0x1f00,
		[VAL_10M_0].src_vaild_index = 13,
		[VAL_10M_0].dst_add = 0x24,
		[VAL_10M_0].dst_vaild_index = 16,
		[VAL_10M_0].bind_train_array = train_10_array,
		[VAL_10M_0].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_0].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,

		[VAL_10M_1].name = "val_10M_1",
		[VAL_10M_1].src_add = REG_PMU_EPHY_PARAM,
		[VAL_10M_1].src_mask = 0x1f00,
		[VAL_10M_1].src_vaild_index = 13,
		[VAL_10M_1].dst_add = 0x1308,
		[VAL_10M_1].dst_vaild_index = 0,
		[VAL_10M_1].bind_train_array = train_10_array,
		[VAL_10M_1].bind_train_size = ARRAY_SIZE(train_10_array),
		[VAL_10M_1].usr_train_offset =
		REFIX_10M_TRAIN_DATA_OFFSET,
};

void dump_phy_train_val(struct s_train_val *p_train)
{
	printf("------------GAP_LINE---------------\n");
	printf("name            : %s\n", p_train->name);
	printf("src_add         : %08x\n", p_train->src_add);
	printf("src_mask        : %08x\n", p_train->src_mask);
	printf("src_vaild_index : %08x\n", p_train->src_vaild_index);
	printf("dst_add         : %08x\n", p_train->dst_add);
	printf("dst_vaild_index : %08x\n", p_train->dst_vaild_index);
	printf("usr_train_offset: %d\n", p_train->usr_train_offset);
}


void parse_train_data(struct s_train_val *p_train)
{
	unsigned long test_data;
	int i;
	unsigned int temp_data;
	unsigned int vaild_bit_pos;
	int max_offset, low_offset;
	unsigned int *array;
	unsigned int size;

	array = p_train->bind_train_array;
	size = p_train->bind_train_size;
	test_data = p_train->src_mask;
	vaild_bit_pos = find_first_bit(&test_data, 32);

	if ((!array) ||
	((p_train->src_mask >> vaild_bit_pos) != (size - 1))) {
		printf("para error..\n");
		return;
	}

	temp_data = GET_REG(p_train->src_add);
	if (temp_data & (1 << p_train->src_vaild_index)) {
		/*got vaild val*/
		temp_data &= p_train->src_mask;
		temp_data >>= vaild_bit_pos;
		printf("[%s] :: train val %d\n", p_train->name, temp_data);
		/*find index*/
		for (i = 0; i < size; i++) {
			if (temp_data == array[i]) {
				max_offset = (size - 1) - i;
				low_offset = 0 - i;
				break;
			}
		}

		if ((p_train->usr_train_offset < low_offset) ||
		(p_train->usr_train_offset > max_offset)) {
			printf("offset [%d] should limit in [%d , %d]\n",
			p_train->usr_train_offset, low_offset, max_offset);
			return;
		}
		//fix array idx..
		i += p_train->usr_train_offset;
		temp_data = array[i];
		/*printf("fix idx :: [%d] = %d\n", i, temp_data);*/
	} else {
		temp_data = 0;
		printf("[%s] :: use default train data %d\n",
		p_train->name, temp_data);
	}
	temp_data &= (p_train->src_mask >> vaild_bit_pos);
	SET_REG_M(REG_EPHY_BASE + p_train->dst_add,
	temp_data << p_train->dst_vaild_index,
	(p_train->src_mask >> vaild_bit_pos) << p_train->dst_vaild_index);
}


static void fh_internal_phy_reset(void){
	int idx;

	printf("fh internal phy reset go...\n ");
	SET_REG_M(REG_EPHY_BASE + 0, 0, 0x3<<7);
	SET_REG(REG_EPHY_BASE + 0x28, 0x00247875);
	SET_REG(REG_EPHY_BASE + 0x1274, 0x3c3);

	SET_REG_M(AP_GMAC_CTRL0, 1<<4, 1<<4); // ephy soft reset
	SET_REG_M(AP_EPHY_CTRL0, 1<<4, 1<<4); // apb ephy soft reset
	udelay(200);
	SET_REG_M(AP_EPHY_CTRL0, 0, 1<<4);
	SET_REG_M(AP_GMAC_CTRL0, 0, 1<<4);

	SET_REG_M(REG_EPHY_BASE + 0x1370, 0x0, 1<<3);
	SET_REG(REG_EPHY_BASE + 0x1274, 0x3c3);
	SET_REG(REG_EPHY_BASE + 0x0b6C, 0xf04);
	SET_REG(REG_EPHY_BASE + 0x1340, 0x0000);
	SET_REG(REG_EPHY_BASE + 0x0bA8, 0x20);
	SET_REG(REG_EPHY_BASE + 0x0018, 0x00c02800);
	SET_REG(REG_EPHY_BASE + 0x001c, 0x00810000);
	SET_REG(REG_EPHY_BASE + 0x0020, 0x0000340c);
	SET_REG(REG_EPHY_BASE + 0x0024, 0x30131500);
	SET_REG(REG_EPHY_BASE + 0x0028, 0x01402800);
	SET_REG(REG_EPHY_BASE + 0x001c, 0xa1800000);
	SET_REG(REG_EPHY_BASE + 0x0028, 0x00402800);
	SET_REG(REG_EPHY_BASE + 0x0014, 0x06000000);
	SET_REG(REG_EPHY_BASE + 0x0020, 0x2340c);
	SET_REG(REG_EPHY_BASE + 0x000c, 0xba0edfff);
	SET_REG(REG_EPHY_BASE + 0x0010, 0x7fcbf9de);
	SET_REG(REG_EPHY_BASE + 0x0b98, 0xd150);
	SET_REG(REG_EPHY_BASE + 0x1224, 0);
	SET_REG(REG_EPHY_BASE + 0x12f0, 0);
	SET_REG(REG_EPHY_BASE + 0x0bc0, 0x7de);
	SET_REG(REG_EPHY_BASE + 0x0bc8, 0x09de);
	SET_REG(REG_EPHY_BASE + 0x070c, 0x0401);
	SET_REG(REG_EPHY_BASE + 0x0a84, 0x1d20);
	SET_REG(REG_EPHY_BASE + 0x06d4, 0x3130);
	SET_REG(REG_EPHY_BASE + 0x0a6c, 0x0818);
	SET_REG(REG_EPHY_BASE + 0x0aec, 0x1000);
	SET_REG(REG_EPHY_BASE + 0x0658, 0x1c00);
	SET_REG(REG_EPHY_BASE + 0x07d4, 0x6900);
	SET_REG(REG_EPHY_BASE + 0x06b8, 0x4);
	SET_REG(REG_EPHY_BASE + 0x06E4, 0x04a0);
	SET_REG(REG_EPHY_BASE + 0x0BBC, 0x1759);
	SET_REG(REG_EPHY_BASE + 0x0bf8, 0x0100);
	SET_REG(REG_EPHY_BASE + 0x0794, 0x9000);
	SET_REG(REG_EPHY_BASE + 0x0788, 0xf);
	SET_REG(REG_EPHY_BASE + 0x1378, 0x2338);
	SET_REG_M(REG_EPHY_BASE + 0x0, 0x20<<24, 0xff<<24);
	SET_REG_M(REG_EPHY_BASE + 0x4, 0x18, 0xff);
	SET_REG(REG_EPHY_BASE + 0x0680, 0x0552);
	SET_REG(REG_EPHY_BASE + 0x1274, 0);
	SET_REG(REG_EPHY_BASE + 0x0b6C, 0x704);
	SET_REG(REG_EPHY_BASE + 0x1340, 0);
	SET_REG(REG_EPHY_BASE + 0x0ba8, 0);
	SET_REG(REG_EPHY_BASE + 0x06c8, 0xc000);
	SET_REG(REG_EPHY_BASE + 0x06e0, 0x8508);
	SET_REG(REG_EPHY_BASE + 0x1328, 0x0065);
	SET_REG(REG_EPHY_BASE + 0x076c, 0x0430); //add link pulse thrh H
	SET_REG(REG_EPHY_BASE + 0x06b4, 0xfd00); //enable auto crossover in 100t and 10t
	SET_REG(REG_EPHY_BASE + 0x1360, 0x3f37);

	SET_REG_M(REG_EPHY_BASE + 0x0778, 0x24 << 8, 0xff << 8);
	SET_REG_M(REG_EPHY_BASE + 0x077c, 0x24, 0xff);

	SET_REG(REG_EPHY_BASE + 0xb10, 0x5000);
	SET_REG(REG_EPHY_BASE + 0xb14, 0x8000);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x000e);
	SET_REG(REG_EPHY_BASE + 0xb20, 0x000e);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x000f);
	SET_REG(REG_EPHY_BASE + 0xb20, 0x0035);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x0000);
	SET_REG(REG_EPHY_BASE + 0xb10, 0x0000);
	SET_REG(REG_EPHY_BASE + 0xb14, 0x0000);

	//led
	SET_REG(REG_EPHY_BASE + 0x7ec, 0x8a6);
	SET_REG(REG_EPHY_BASE + 0x2c, 0x10);
	SET_REG(REG_EPHY_BASE + 0x07f8, 0x325);

	for (idx = 0; idx < ARRAY_SIZE(train_array); idx++) {
		/*dump_phy_train_val(&train_array[idx]);*/
		parse_train_data(&train_array[idx]);
	}

}

static void fh_internal_phy_link_up_cb(void *pri)
{
	SET_REG(REG_EPHY_BASE + 0x0b10, 0x5000);
	SET_REG(REG_EPHY_BASE + 0x0b14, 0x8000);
	SET_REG(REG_EPHY_BASE + 0x0b1c, 0x000e);
	SET_REG(REG_EPHY_BASE + 0x0b20, 0x0004);
	SET_REG(REG_EPHY_BASE + 0x0aec, 0x1800);
	SET_REG(REG_EPHY_BASE + 0x0b10, 0x0000);
	SET_REG(REG_EPHY_BASE + 0x0b14, 0x0000);
}

static void fh_internal_phy_link_down_cb(void *pri)
{
	SET_REG(REG_EPHY_BASE + 0xb10, 0x5000);
	SET_REG(REG_EPHY_BASE + 0xb14, 0x8000);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x000e);
	SET_REG(REG_EPHY_BASE + 0xb20, 0x000e);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x000f);
	SET_REG(REG_EPHY_BASE + 0xb20, 0x0035);
	SET_REG(REG_EPHY_BASE + 0xb1c, 0x0000);
	SET_REG(REG_EPHY_BASE + 0xb10, 0x0000);
	SET_REG(REG_EPHY_BASE + 0xb14, 0x0000);
}

static void fh_external_phy_link_up_cb(void *pri)
{
	struct phy_device *p_phy;

#if(0)
	p_phy = (struct phy_device *)pri;
	if(!p_phy)
		return;

	if(p_phy->phy_id == FH_GMAC_PHY_RTL8201){
		p_phy->bus->write(p_phy->bus, 0, 0, 31, 7);
		p_phy->bus->write(p_phy->bus, 0, 0, 19, 0xc00c);
		if(p_phy->speed == 100)
			p_phy->bus->write(p_phy->bus, 0, 0, 17, 0x28);
		else if(p_phy->speed == 10)
			p_phy->bus->write(p_phy->bus, 0, 0, 17, 0x18);

		p_phy->bus->write(p_phy->bus, 0, 0, 31, 0);
	}
#endif
}

static void fh_external_phy_link_down_cb(void *pri)
{

}

static struct phy_driver phy_usr_driver_obj[] = {
	{
		.name = "Generic PHY 0",
		// for FPGA, use ext phy
		//.phy_info[0].phy_sel = EXTERNAL_PHY,
		//.phy_info[0].phy_reset = fh_external_phy_0_reset,
		//.phy_info[0].sync_mac_spd = gmac_0_set_spd,
		//.phy_info[0].phy_inf = PHY_INTERFACE_MODE_RMII,
		//.phy_info[0].brd_link_up_cb = fh_external_phy_link_up_cb,
		//.phy_info[0].brd_link_down_cb = fh_external_phy_link_down_cb,

		.phy_info[0].phy_sel = INTERNAL_PHY,
		.phy_info[0].phy_reset = fh_internal_phy_reset,
		//fullhan ephy clk don't need sync with mac
		.phy_info[0].sync_mac_spd = 0,
		.phy_info[0].phy_inf = PHY_INTERFACE_MODE_MII,
		.phy_info[0].brd_link_up_cb = fh_internal_phy_link_up_cb,
		.phy_info[0].brd_link_down_cb = fh_internal_phy_link_down_cb,
		.inf_set = phy_0_inf_set,
		.phy_sel = phy_0_sel_func,
	},
};


int board_eth_init(bd_t *bis)
{
	int rc = 0;

#ifdef CONFIG_FH_QOS_GMAC
	SET_REG(AP_EPHY_CTRL0,0xc);
	int i;
	for(i = 0; i < MAX_MAC_CTL; i++)
		genphy_init_with_usr_cfg(&phy_usr_driver_obj[i]);

	for(i = 0; i < MAX_MAC_CTL; i++){
		if(fh_qos_mac_initialize(bis))
				rc++;
	}
#endif

	return rc;
 }



static void clock_init(void)
{
	SET_REG_M(DMC_CLK_CTRL,0x1<<2|0x1<<3|0x1<<4,0x1<<2|0x1<<3|0x1<<4);
	SET_REG_M(CEN_PERI_APB_CLK_CTRL,0x1<<16|0x1<<19,0x1<<16|0x1<<19);
	SET_REG_M(AP_MTX_CLK_CTRL0,0x1<<16|0x1<<17,0x1<<16|0x1<<17);
	SET_REG_M(VEU_SYS_CLK_CFG1,0x1<<15|0x1<<19,0x1<<15|0x1<<19);
	SET_REG_M(CKG_SPIC_CFG,0x102,0xff07);
	SET_REG_M(VEU_SYS_CLK_CFG2,BIT(11),BIT(11)); //apb_rtc_en=1

	return;
}

#ifdef CONFIG_USB
void fh_usb_power_enable(void)
{
	SET_REG_M(0x1ca00018, 0x00100000, 0x80100800);
	gpio_direction_output(47, 1);
	
	SET_REG_M(0x1ca00020, 0xC0000000, 0xC0000000);
	udelay(1000);
	SET_REG_M(0x1ca00020, 0x0, 0xC0000000);
}
#endif

int board_init(void)
{
	clock_init();
	/* set all dma handshake to dma0 */
	//SET_REG(REG_DMA_SEL_LOW, 0);
	//SET_REG(REG_DMA_SEL_HIGH, 0);
	//SET_REG(REG_DMA0_AXCACHE, 0);
	//SET_REG(REG_DMA1_AXCACHE, 0);
	/* Enable Ctrlc */
	/*console_init_f();*/
	gd->bd->bi_arch_number = MACH_TYPE_QM102V;
	/* adress of boot parameters */
	gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
	fh_pinctrl_init(CEN_PIN_REG_BASE + 0x8);
//	if (get_boot_media() > 2)
//		fh_pinctrl_sdev("EMMC", 0);
	/*hw_board_wdt_init();*/
#ifdef CONFIG_USB
	fh_usb_power_enable();
#endif
#ifdef CONFIG_FH_MC_DMA
	 dma_init();
#endif

#if defined CONFIG_FH_AES_V2 && defined CONFIG_FH_ALGORITHM_CORE
	fh_aes_probe();
#endif

#ifdef CONFIG_FH_SPI
extern struct spi_slave *fh_spi_setup_slave(unsigned int bus, unsigned int cs,
				unsigned int max_hz, unsigned int mode);
	spi_init();
	spi_bus_register(0, fh_spi_setup_slave);
	spi_bus_register(1, fh_spi_setup_slave);
#endif
	return 0;
}

int dram_init(void)
{
	gd->ram_size = PHYS_SDRAM_SIZE;
	return 0;
}

void dram_init_banksize(void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE;
}

void reset_cpu (ulong addr)
{
	SET_REG(REG_WR_PROTECT, 0x5a5a5a5a);
	SET_REG(REG_GLB_RESET, SW_GLB_RST);
}

#ifdef CONFIG_RESET_PHY_R
void reset_phy(void)
{
#ifdef CONFIG_MACB
	/*
	 * Initialize ethernet HW addr prior to starting Linux,
	 * needed for nfsroot
	 */
	eth_init(gd->bd);
#endif
}
#endif

void enable_caches(void)
{
	// empty func to avoid WARNING: Caches not enabled
}

#ifdef CONFIG_FH_MMC

void fh_mci_sys_init(unsigned int slot_id)
{


}
#endif





#ifdef CONFIG_GENERIC_MMC
#ifdef CONFIG_FH_MMC
extern int fh_mmc_init(int index);
#endif

int board_mmc_init(bd_t *bis)
{
    int ret = 0;

#ifdef CONFIG_MSHC_LITE_FH
	if (get_boot_media() > 2){
		ret = fh_mshc_lite_int(&mshc_plat);
		if (ret) {
				printf("No EMMC device found !\n");
		}
	}
#endif

#ifdef CONFIG_FH_MMC
#ifdef FH_MMC_SDC0
	ret = fh_mmc_init(0);
	if (ret)
	    printf("No SD0 device found !\n");
#endif
#ifdef FH_MMC_SDC1
    ret = fh_mmc_init(1);
    if (ret)
        printf("No SD1 device found !\n");
#endif
#endif
    return ret;
}
#endif

void do_arc_jump(ulong addr)
{
}




#ifdef CONFIG_OPTEE
#include <dm/platdata.h>
#include <linux/arm-smccc.h>

static void optee_smccc_smc(unsigned long a0, unsigned long a1,
			    unsigned long a2, unsigned long a3,
			    unsigned long a4, unsigned long a5,
			    unsigned long a6, unsigned long a7,
			    struct arm_smccc_res *res)
{
	arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
}

struct {
	void *invoke_fn;
} optee_pdata = {optee_smccc_smc};

U_BOOT_DEVICE(optee) = {
	.name = "optee",
	.platdata = &optee_pdata,
};
#endif
